package protomsg

import math "math"

/*
坐标操作库

*/

var (
	//无效坐标
	_invalid_Vector3 = &Vector3{
		X: math.MaxFloat64,
		Y: math.MaxFloat64,
		Z: math.MaxFloat64,
	}
)

// Vector3_Invalid 返加一个无效的值 ，未赋值之前
func Vector3_Invalid() Vector3 {
	return *_invalid_Vector3
}

// NewVector3 创建一个新的矢量
func NewVector3(x, y, z float64) Vector3 {
	return Vector3{
		X: x,
		Y: y,
		Z: z,
	}
}

// IsInValid 是否有效
func (v Vector3) IsInValid() bool {
	return v.IsEqual(Vector3_Invalid())
}

// 坐标无效化
func (v *Vector3) InValid() {
	v.X = math.MaxFloat32
	v.Y = math.MaxFloat32
	v.Z = math.MaxFloat32
}

// IsEqual 相等
func (v Vector3) IsEqual(r Vector3) bool {
	if v.X-r.X > math.SmallestNonzeroFloat32 ||
		v.X-r.X < -math.SmallestNonzeroFloat32 ||
		v.Y-r.Y > math.SmallestNonzeroFloat32 ||
		v.Y-r.Y < -math.SmallestNonzeroFloat32 ||
		v.Z-r.Z > math.SmallestNonzeroFloat32 ||
		v.Z-r.Z < -math.SmallestNonzeroFloat32 {
		return false
	}

	return true
}

// IsEqualXYZ
func (v Vector3) IsEqualXYZ(r Vector3) bool {
	return int64(v.X*100) == int64(r.X*100) &&
		int64(v.Y*100) == int64(r.Y*100) &&
		int64(v.Z*100) == int64(r.Z*100)
}

// IsEqualXZ 不判断高度
func (v Vector3) IsEqualXZ(r Vector3) bool {
	return int64(v.X*100) == int64(r.X*100) &&
		int64(v.Z*100) == int64(r.Z*100)
}

// Add 加
func (v Vector3) Add(o Vector3) Vector3 {
	return Vector3{
		X: v.X + o.X,
		Y: v.Y + o.Y,
		Z: v.Z + o.Z,
	}
}

// AddS 加到自己身上
func (v *Vector3) AddS(o Vector3) {
	v.X += o.X
	v.Y += o.Y
	v.Z += o.Z
}

// Sub 减
func (v Vector3) Sub(o Vector3) Vector3 {
	return Vector3{
		X: v.X - o.X,
		Y: v.Y - o.Y,
		Z: v.Z - o.Z,
	}
}

// SubS 自已身上减
func (v *Vector3) SubS(o Vector3) {
	v.X -= o.X
	v.Y -= o.Y
	v.Z -= o.Z
}

// Mul 乘
func (v Vector3) Mul(o float64) Vector3 {
	return Vector3{
		X: v.X * o,
		Y: v.Y * o,
		Z: v.Z * o,
	}
}

// MulS 自己乘
func (v *Vector3) MulS(o float64) {
	v.X *= o
	v.Y *= o
	v.Z *= o
}

/*
向量的点积（Dot Product）也叫数量积、内积，是两个向量的乘积的数量级的余弦值,
用于计算两个向量之间的夹角。具体而言，对于两个三维向量A=(Ax,Ay,Az)和B=(Bx,By,Bz)，它们的点积为：
A · B = Ax*Bx + Ay*By + Az*Bz
点积的结果是一个实数，可以用来判断两个向量的相似度以及方向是否相同。
如果点积结果为0，则表示两个向量垂直；
如果点积结果大于0，则表示两个向量夹角小于90度，且方向相同；
如果点积结果小于0，则表示两个向量夹角大于90度，且方向相反。
*/
// Dot 点积
func (v Vector3) Dot(o Vector3) float64 {
	return v.X*o.X + v.Y*o.Y + v.Z*o.Z
}

// 点积 忽略Y
func (v Vector3) Dot2(o Vector3) float64 {
	return v.X*o.X + v.Z*o.Z
}

/*
向量叉积（Cross Product），也称为向量积、外积，
是两个三维向量 A = (Ax, Ay, Az) 和 B = (Bx, By, Bz) 所确定的平行四边形面积所对应的向量，可用以下公式表示：

```
A × B = (AyBz − AzBy)i + (AzBx − AxBz)j + (AxBy − AyBx)k
```

其中，i、j、k分别为三维空间中的基向量。

叉积的结果是一个新的向量，与原来的两个向量垂直。另外，叉积也有如下性质：

1. 对于任意的向量A和B，有A×B = -B×A。
2. 若A和B共线，则它们的叉积为零向量。
3. 计算叉积的结果与向量AB所在平面垂直，并且遵循右手定则，
即将右手的食指从向量A旋转到向量B的方向，并将中指弯曲90度，此时拇指所指的方向即为叉积所在的方向。

叉积常用于计算平面的法向量、判断点在平面上方还是下方等问题。它在计算机图形学、物理学等领域中广泛应用。
*/
// Cross 叉乘
func (v Vector3) Cross(o Vector3) Vector3 {
	return Vector3{
		X: v.Y*o.Z - v.Z*o.Y,
		Y: v.Z*o.X - v.X*o.Z,
		Z: v.X*o.Y - v.Y*o.X,
	}
}

// Len 获取长度
// 这个函数已经不考虑Y轴方向的问题；
func (v Vector3) Len() float64 {
	return math.Sqrt(float64(v.LenPow2()))
}

// 长度 的平方
// 这个函数已经不考虑Y轴方向的问题；
func (v Vector3) LenPow2() float64 {
	return v.X*v.X + v.Z*v.Z
}

// 判断自己的长度是否超出r的范围
// Y轴方向已忽略，而且无开方
func (v Vector3) IsOutOfRange(r float64) bool {
	return v.LenPow2() > NewVector3(r, 0, 0).LenPow2()
}

// 判断自己的长度是否超出r的范围
// Y轴方向已忽略，而且无开方
func (v Vector3) IsOutOfRangeInt32(r int32) bool {
	return v.IsOutOfRange(float64(r))
}

// 向量归一化
func (v *Vector3) Normalize() {
	len := v.Len()
	if len < math.SmallestNonzeroFloat64 {
		return
	}

	v.X = v.X / len
	v.Y = v.Y / len
	v.Z = v.Z / len
}

//------------------------------------------------------------------------

// NewVector2 创建一个新的Vector2
func NewVector2(x, y float64) Vector2 {
	return Vector2{
		x,
		y,
	}
}

// Vector2_Zero 返回零值
func Vector2_Zero() Vector2 {
	return Vector2{
		0,
		0,
	}
}

// Vector2_Invalid 返加一个无效的值 ，未赋值之前
func Vector2_Invalid() Vector2 {
	return Vector2{
		math.MaxFloat64,
		math.MaxFloat64,
	}
}

// IsInValid 是否有效
func (v Vector2) IsInValid() bool {
	return v.IsEqual(Vector2_Invalid())
}

// IsEqual 相等
func (v Vector2) IsEqual(r Vector2) bool {
	return v.X == r.X && v.Y == r.Y
}

// Add 加
func (v Vector2) Add(o Vector2) Vector2 {
	return Vector2{v.X + o.X, v.Y + o.Y}
}

// AddS 加到自己身上
func (v *Vector2) AddS(o Vector2) {
	v.X += o.X
	v.Y += o.Y
}

// Sub 减
func (v Vector2) Sub(o Vector2) Vector2 {
	return Vector2{v.X - o.X, v.Y - o.Y}
}

// SubS 自已身上减
func (v *Vector2) SubS(o Vector2) {
	v.X -= o.X
	v.Y -= o.Y
}

// Mul 乘
func (v Vector2) Mul(m float64) Vector2 {
	return Vector2{
		v.X * m,
		v.Y * m,
	}
}

// Dot 点乘
func (v Vector2) Dot(o Vector2) float64 {
	return v.X*o.X + v.Y*o.Y
}

// Len 获取长度
func (v Vector2) Len() float64 {
	return float64(math.Sqrt(float64(v.Dot(v))))
}

// Cross 叉乘
func (v Vector2) Cross(o Vector2) float64 {
	return v.X*o.Y - v.Y*o.X
}

func (v *Vector2) Normalize() {
	len := v.Len()
	if len < math.SmallestNonzeroFloat64 {
		return
	}

	v.X = v.X / len
	v.Y = v.Y / len
}
